package com.design.classroommanagement.api.dao


import com.design.classroommanagement.api.BaseModel
import com.design.classroommanagement.util.DBUtils
import com.laughing.lib.utils.Logs
import com.laughing.lib.utils.urlDecode
import com.laughing.lib.utils.urlEncode
import okio.ByteString.Companion.encode
import java.sql.ResultSet

interface BaseDao<T : BaseModel> {
    suspend fun add(t: T): Boolean {
        val query = getDbMap(t)
        val keySb = StringBuilder()
        val valueSb = StringBuilder()
        val size = query.size

        query.keys.forEachIndexed { index, key ->
            keySb.append(key)
            valueSb.append("\'${query[key]?.toString()?.urlEncode()}\'")

            if (size >= 2 && index < size - 1) {
                keySb.append(",")
                valueSb.append(",")
            }
        }

        val sql = "insert into ${getTableName()} (${keySb}) VALUES(${valueSb})"
        Logs.d("add ->> $sql")
        val conn = DBUtils.initConnect() ?: return false
        val statement = conn.createStatement();
        try {
            statement.execute(sql)
        } catch (e: Exception) {
            e.printStackTrace()
            return false
        }
        return true
    }

    suspend fun delete(t: T) {
        val sql = "delete from ${getTableName()} where id = '${t.getKeyId()}'"
        Logs.d("delete sql ->> $sql")
        val conn = DBUtils.initConnect() ?: return
        val prepare = conn.prepareStatement(sql)

        val rs = prepare.execute()
    }

    suspend fun update(t: T): Boolean {
        val updateParam = StringBuilder()
        val query = getDbMap(t)

        val size = query.size

        query.keys.forEachIndexed { index, key ->

            updateParam.append(key).append("=").append("\'${query[key]?.toString()?.urlEncode()}\'")

            if (size >= 2 && index < size - 1) {
                updateParam.append(",")
            }
        }

        val sql =
            "UPDATE ${getTableName()} SET ${updateParam} WHERE id = '${t.getKeyId()}'"

        Logs.d("update ->> $sql")
        val conn = DBUtils.initConnect() ?: return false
        val statement = conn.createStatement();
        statement.execute(sql)
        return true
    }

    suspend fun query(queryBuilder: MutableMap<String, String>.() -> Unit = {}): List<T> {
        val result = mutableListOf<T>()

        val paramsSb = StringBuilder()
        val valueList = mutableListOf<String>()
        val query = mutableMapOf<String, String>()
        queryBuilder(query)
        val size = query.size

        query.keys.forEachIndexed { index, key ->
            if (index == 0) {
                paramsSb.append(" where ")
            }
            val value = query[key] ?: ""
            paramsSb.append(key).append("=").append("\"${value.urlEncode()}\"")
            valueList.add(value)

            if (size >= 2 && index < size - 1) {
                paramsSb.append(" and ")
            }
        }

        val sql = "select * from ${getTableName()} $paramsSb"
        Logs.d("query ->> $sql")
        val conn = DBUtils.initConnect() ?: return result
        val statement = conn.createStatement();
        val rs = statement.executeQuery(sql)

        while (rs.next()) {
            result.add(getData(rs))
        }

        return result
    }

    fun getData(rs: ResultSet): T
    fun getTableName(): String

    fun getDbMap(t: T): HashMap<String, Any>
}

fun ResultSet.getDecodeObject(key: String): Any? {
    var value = getObject(key)
    if (value is String) {
        value = value.urlDecode()
    }
    return value
}